﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tedds_Tool;
using System.Diagnostics;
using System.Threading;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows;
using GUI.Custom_Classes;
using WinForms = System.Windows.Forms;
using Compiled_Tests.Utils;
using System.Windows.Input;
using Tedds_Tool.Instructions;
using Compiled_Tests.ProcessWrappers;
using Compiled_Tests;
using Tedds_Tool.Automatables;
using LEET.LEETCommon;
using StandardScriptItems;
using CommonInterfaces.Models;
using LEET.LEETCommon.Model;
using System.Windows.Media;

namespace GUI.Tabs
{
    class RecordingController
    {
        Recorder recorder;
        AutomationElement Current_Target;
        RecordingState Record_Button;
        WindowSelector Window_Selector;
        SetText Current_Target_Info;
        ScriptViewer Script_Viewer;
        private NameUniquenessGarentee uniq;
        IScriptFinder scriptFinder;
        IAlerts alerts;
        ILEETFactory Factory;

        public RecordingController(
            ILEETFactory factory, 
            IScript Script_Viewer, 
            IAlerts alerts, 
            IScriptFinder scriptFinder, 
            SetText Current_Target_Info, 
            Button Window_Selector, 
            Button Record_Button)
        {
            Factory = factory;
            this.scriptFinder = scriptFinder;
            uniq = new NameUniquenessGarentee();
            this.Script_Viewer = Script_Viewer as ScriptViewer;
            this.Current_Target_Info = Current_Target_Info;
            this.Record_Button = new RecordingState(Record_Button);
            this.alerts = alerts;
            this.Window_Selector = new WindowSelector(Window_Selector, alerts);
            this.Window_Selector.ProcessTargeted += AddToRecording;
            
            Current_Target = null;
        }

        #region Recording Functionality

        private bool Recording()
        {
            return recorder != null && recorder.Recording;
        }

        private void Start_and_Record(String exe)
        {
            Process p = new Process();
            p.StartInfo = new ProcessStartInfo(exe);
            p.Start();

            Script_Viewer.AddScriptItem(new Event_Pair("START\t| " + exe));
            AddToRecording(p);
        }

        private IProcess IProcFactory(Process p)
        {
            return new ProcessWrapper(p, uniq.MakeUnique(p.ProcessName));
        }

        private void AddToRecording(Process p)
        {
            Record_Button.Initializing();
            if (!Recording())
            {
                recorder = new Recorder(IProcFactory, Callback, Factory, Factory.Box as Box);
                uniq = new NameUniquenessGarentee();
            }

            try
            {
                IProcess pro = IProcFactory(p);
                recorder.Record(pro);
                Record_Button.Running();
            }
            catch (Exception e)
            {
                alerts.Error(e.Message);
            }
            
            Current_Target = AutomationElement.FromHandle(p.MainWindowHandle);
            update_Current_Target_Info();
        }

        private void OnCurrentRecordingFinished(Tedds_Tool.Recorder.RecordingEvent e)
        {
            if(Recording())
                recorder.RecordingStopped += e;
        }

        private void StopRecording()
        {
            Record_Button.Stopping();
            
            if(recorder != null)
                recorder.Shutdown();
            Current_Target = null;             //prevents a crash, but there needs to be a better solution
            update_Current_Target_Info();
            
            Record_Button.Stopped();
        }

        private void update_Current_Target_Info()
        {
            string text = "";
            if (Current_Target != null)
            {
                text += "Name:\t" + Current_Target.Current.Name;
                text += "\nAID:\t" + Current_Target.Current.AutomationId;
                text += "\nPID:\t" + Current_Target.Current.ProcessId;
            }
            Current_Target_Info.Text = text;
        }

        
        #endregion

        public void Record_Button_Click(object sender, RoutedEventArgs e)
        {
            if (Recording())    //Was recording, need to stop now
            {
                StopRecording();
            }
            Record_Button.Stopped();
        }

        private void Callback(IEvent_Pair ep)
        {
            Script_Viewer.Dispatcher.BeginInvoke((Action)delegate
            {
                Script_Viewer.AddScriptItem(ep);
            });
        }

        public void Startup_and_Record_Click(object sender, RoutedEventArgs e)
        {
            WinForms.OpenFileDialog ofd = new WinForms.OpenFileDialog();
            ofd.InitialDirectory = "C:\\";
            ofd.Filter = "Executable (*.exe)|*.exe";
            WinForms.DialogResult result = ofd.ShowDialog();
            if (result != System.Windows.Forms.DialogResult.OK)
                return;
            (sender as FrameworkElement).Dispatcher.Invoke((System.Action)delegate()
            {
                Start_and_Record(ofd.FileName);
            });
        }

        public void Window_Selector_Click(object sender, RoutedEventArgs e)
        {
            if (!Window_Selector.IsActive)
            {
                Window_Selector.IsActive = true;
            }
        }

        public void Add_Button_Click(object sender, RoutedEventArgs e)
        {
            ScriptBuilder sb = Factory.CreateScriptBuilder() as ScriptBuilder;
            sb.Margin = new Thickness(10, 0, 0, 0);
            Script_Viewer.AddScriptItem(sb);
            ScriptViewer.ScrollToBottom(Script_Viewer.LineNumbers);
        }

        private IElementState GetElementState()
        {
            if (Recording())
            {
                return recorder.ElementState;
            }
            else
            {
                return new ElementState();
            }
        }

        private IList<String> GetCurrentTargets()
        {
            if (Recording())
            {
                return recorder.Processes;
            }
            else
            {
                return new List<String>();
            }
        }

        public void Remove_Button_Click(object sender, RoutedEventArgs e)
        {
            Script_Viewer.RemoveSelected();
        }

        public void ShutDown()
        {
            Window_Selector.IsActive = false;
            StopRecording();
        }
    }
}
